from typing import List, Dict, Any
import logging

logger = logging.getLogger(__name__) 

import re

class ExpectedMatch:
    """
    用于在命令输出内容中进行匹配期望输出，支持正则表达式
    """
    
    def __init__(self, expected: List[Dict[str, Any]], unexpected: List[Dict[str, Any]]):

        """
        初始化期望输出和不期望输出

        Args:
            expected: 期望输出列表
            unexpected: 不期望输出列表
            use_regex: 是否启用正则表达式匹配，默认True
        """
        self.expected = expected
        self.unexpected = unexpected
        self.compiled_expected = dict()
        self.compiled_unexpected = dict()

        # 若缺失字段，则使用默认值
        for item in self.expected:
            if 'match_times' not in item:
                item['match_times'] = 1
            if 'use_regex' not in item:
                item['use_regex'] = False
        for item in self.unexpected:
            if 'match_times' not in item:
                item['match_times'] = 0
            if 'use_regex' not in item:
                item['use_regex'] = False

        
        # 初始化期望输出
        for i in range(len(expected)):
            item = self.expected[i]
            self.expected[i]['match_times'] = int( self.expected[i]['match_times'] )
            if item['use_regex']:
                try:
                    self.compiled_expected[item['pattern']] = re.compile(item['pattern'], re.IGNORECASE | re.MULTILINE)
                except re.error as e:
                    # 如果正则表达式编译失败，回退到字符串匹配
                    logger.warning(f"警告: 正则表达式 '{item['pattern']}' 编译失败，回退到字符串匹配: {e}")
                    self.compiled_expected[item['pattern']] = None
        
        # 初始化不期望输出
        for i in range(len(unexpected)):
            item = self.unexpected[i]
            self.unexpected[i]['match_times'] = int( self.unexpected[i]['match_times']) 
            if item['use_regex']:
                try:
                    self.compiled_unexpected[item['pattern']] = re.compile(item['pattern'], re.IGNORECASE | re.MULTILINE)
                except re.error as e:
                    # 如果正则表达式编译失败，回退到字符串匹配
                    logger.warning(f"警告: 正则表达式 '{item['pattern']}' 编译失败，回退到字符串匹配: {e}")
                    self.compiled_unexpected[item['pattern']] = None

    def _match_pattern(self, pattern: str, compiled_pattern,use_regex: bool, output: str) -> int:

        """
        根据是否启用正则表达式进行匹配
        
        Args:
            pattern: 原始模式字符串
            compiled_pattern: 编译后的正则表达式对象（可能为None）
            output: 待匹配的输出内容
            
        Returns:
            bool: 是否匹配成功
        """
        if use_regex and compiled_pattern is not None:
            # 使用正则表达式匹配，返回匹配次数
            match_count = compiled_pattern.findall(output)
            return len(match_count)
        else:
            # 使用字符串包含匹配（原始方式），返回匹配次数
            match_count = output.count(pattern)
            return match_count

    def match(self, output: str):
        """
        根据命令输出进行匹配检查
        
        Args:
            output: 命令的标准输出
            
        Returns:
            内部记录匹配结果
        """
        # 检查是否匹配期望输出
        for i in range(len(self.expected)):
            item = self.expected[i]
            compiled_pattern = self.compiled_expected.get(item['pattern']) if item['use_regex'] else None
            tmp = self._match_pattern(item['pattern'], compiled_pattern,item['use_regex'], output)

            if tmp>0:
                self.expected[i]['match_times'] -= tmp                

        # 检查是否匹配不期望输出
        for i in range(len(self.unexpected)):
            item = self.unexpected[i]
            compiled_pattern = self.compiled_unexpected.get(item['pattern']) if item['use_regex'] else None
            tmp = self._match_pattern(item['pattern'], compiled_pattern,item['use_regex'], output)
            if tmp>0:
                self.unexpected[i]['match_times'] -= tmp


    def check(self):
        """
        检查是否所有期望输出都匹配到了，最后的检查
        
        Returns:
            tuple: (是否成功, 异常对象或None)
        """
        expect_str = ""
        unexpected_str = ""

        is_success = True
        
        # 检查期望输出
        for item in self.expected:
            if item['match_times'] > 0:  # 全部expected匹配成功且每个都匹配到指定次数，才会返回true
                expect_str = expect_str + " " + item['pattern'] + f"还差({item['match_times']})次匹配"
                is_success = False
                
        # 检查不期望输出
        for item in self.unexpected:
            if item['match_times'] < 0:  # 全部unexpected未匹配，或均满足容忍次数，才会返回true
                unexpected_str = unexpected_str + " " + item['pattern']+f"多匹配了({-item['match_times']})次"
                is_success = False
        
        if is_success:
            return True, None
        else:
            error_msg = ""
            if expect_str.strip():
                error_msg += f"期望输出未匹配到：{expect_str.strip()}"
            if unexpected_str.strip():
                if error_msg:
                    error_msg += "，"
                error_msg += f"不期望输出匹配到了：{unexpected_str.strip()}"
            
            return is_success, Exception(error_msg)
        
    def check_expected(self):
        '''
        检查是否所有期望输出都匹配到了,且每个都匹配到了指定次数
        Returns:
            bool: 是否所有期望输出都匹配到了
        '''
        if not self.expected:
            return False
        is_success = True
        for item in self.expected:
            if item['match_times'] > 0:  # 全部expected匹配成功且每个都匹配到指定次数，才会返回true
                is_success = False
                break
        return is_success

    def check_unexpected(self):
        '''
        检查是否所有不期望输出都未匹配到，或均满足容忍次数
        Returns:
            bool: 是否所有不期望输出都未匹配到
        '''
        if not self.unexpected:
            return True
        is_success = True
        for item in self.unexpected:
            if item['match_times'] < 0:  # 全部unexpected未匹配，或均满足容忍次数，才会返回true
                is_success = False
                break
        return is_success


    def get_match_results(self) -> Dict[str, Dict[str, int]]:
        """
        获取匹配结果统计
        
        Returns:
            dict: 包含期望和不期望输出的匹配次数统计
        """
        return {
            "expected": {item['pattern']: item['match_times'] for item in self.expected},
            "unexpected": {item['pattern']: item['match_times'] for item in self.unexpected}
        }
